home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / libc / fmt.c < prev    next >
C/C++ Source or Header  |  1990-09-11  |  34KB  |  1,187 lines

  1. /* 
  2.  * fmt.c --
  3.  *
  4.  *    Routines for converting between different formats of data.
  5.  *    A data format includes such things as byte-order and 
  6.  *    alignment. 
  7.  *
  8.  * Copyright 1989 Regents of the University of California
  9.  * Permission to use, copy, modify, and distribute this
  10.  * software and its documentation for any purpose and without
  11.  * fee is hereby granted, provided that the above copyright
  12.  * notice appear in all copies.  The University of California
  13.  * makes no representations about the suitability of this
  14.  * software for any purpose.  It is provided "as is" without
  15.  * express or implied warranty.
  16.  */
  17.  
  18. #ifndef lint
  19. static char rcsid[] = "$Header: /sprite/src/lib/c/etc/RCS/fmt.c,v 1.8 90/09/11 14:17:10 kupfer Exp $ SPRITE (Berkeley)";
  20. #endif /* not lint */
  21. /*LINTLIBRARY*/
  22.  
  23.  
  24. #include <sprite.h>
  25. #include <stdlib.h>
  26. #include <ctype.h>
  27. #include <string.h>
  28. #include <sys.h>
  29. #include "fmt.h"
  30.  
  31. /*
  32.  * Two supported byte-orders.
  33.  */
  34. #define BIG_ENDIAN 0
  35. #define LITTLE_ENDIAN 1
  36.  
  37. /*
  38.  * Structure for each format. Right now formats only include alignment
  39.  * and byte-order. The alignment fields for bytes, halfwords, words,
  40.  * and doublewords are used to align these data types such that their
  41.  * addresses are a multiple of the alignment.  For example, an alignment
  42.  * of 4 indicates that the address of the data must be a multiple of
  43.  * 4. The alignments for structures and unions are used in the same
  44.  * way, except that they represent the minimum alignment. If the
  45.  * structure or union contains a more restrictive data type the more
  46.  * restrictive alignment is used.
  47.  * 
  48.  * There are two supported byte-orders: little-endian and big-endian.
  49.  * If we view a word as an array of 4 bytes, then byte 0 is the most
  50.  * significant byte of the word if a machine is big-endian and the
  51.  * least significant if the machine is little endian.
  52.  */
  53.  
  54. typedef struct {
  55.     int        bAlign;            /* Byte alignment */
  56.     int        hAlign;            /* Halfword alignment */
  57.     int        wAlign;            /* Word alignment */
  58.     int        dAlign;            /* Doubleword alignment */
  59.     int        structMinAlign;        /* Minimum alignment of structures */
  60.     int        unionMinAlign;        /* Minimum alignment of unions */
  61.     int        byteOrder;        /* Byte order. */
  62. } FormatInfo;
  63.  
  64. /*
  65.  * Byte-order and alignment information for each type.
  66.  */
  67. static FormatInfo formatInfo[] = {
  68.     {1,    2, 2, 2, 2, 2, BIG_ENDIAN},           /* 68K */
  69.     {1, 2, 4, 4, 1, 1, LITTLE_ENDIAN},        /* VAX */
  70.     {1, 2, 4, 8, 4, 4, LITTLE_ENDIAN},       /* SPUR */
  71.     {1, 2, 4, 8, 1, 1, LITTLE_ENDIAN},       /* MIPS */
  72.     {1, 2, 4, 8, 1, 1, BIG_ENDIAN},        /* SPARC */
  73.     {1, 2, 2, 2, 1, 1, LITTLE_ENDIAN}        /* Symmetry */
  74. };
  75.  
  76. /*
  77.  * Number of different formats.
  78.  */
  79. static int formatCount = sizeof(formatInfo) / sizeof(FormatInfo);
  80.  
  81. /*
  82.  * Structure to maintain state of current conversion.
  83.  */
  84. typedef struct {
  85.     char        *contPtr;    /* Ptr to position in content string */
  86.     char        *inEndPtr;    /* Ptr to last byte in input buffer */
  87.     char        *inPtr;        /* Ptr to position in input buffer */
  88.     char        *inStartPtr;    /* Starting input pointer. */
  89.     char        *outEndPtr;    /* Ptr to last byte in output buffer */
  90.     char        *outPtr;    /* Ptr to position in output buffer */
  91.     char        *outStartPtr;    /* Starting output pointer. */
  92.     FormatInfo        *inInfoPtr;    /* Ptr to format info for in format */
  93.     FormatInfo        *outInfoPtr;    /* Ptr to format info for out format */
  94. } State;
  95.  
  96. /*
  97.  * Used to convert Swap_Buffer constants to Fmt constants.
  98.  */
  99.  
  100. static int compat[3] = { 1, 4, 3};
  101.  
  102. /*
  103.  * Forward declaration of procedures.
  104.  */
  105. static int    ConvertSequence _ARGS_((Boolean doCopy, int unionIndex,
  106.                     int openChar, State *statePtr));
  107. static int    ConvertStruct _ARGS_((Boolean doCopy, Boolean doingUnion,
  108.                       State *statePtr, int *repCountPtr));
  109. static int    ConvertUnion _ARGS_((Boolean doCopy, Boolean doingUnion,
  110.                      State *statePtr, int *repCountPtr));
  111. static int    ConvertByte _ARGS_((Boolean doCopy, int repCount,
  112.                     State *statePtr));
  113. static int    ConvertHalfWord _ARGS_((Boolean doCopy, int repCount,
  114.                     State *statePtr));
  115. static int    ConvertWord _ARGS_((Boolean doCopy, int repCount,
  116.                     State *statePtr));
  117. static int    ConvertDoubleWord _ARGS_((Boolean doCopy, int repCount,
  118.                       State *statePtr));
  119. static int    CalcComplexAlign _ARGS_((State *statePtr, char **contPtrPtr,
  120.                      int *repCountPtr, int *inAlignPtr,
  121.                      int *outAlignPtr));
  122.  
  123. /*
  124.  * AlignPointer --
  125.  *
  126.  * Macro to increment a pointer to the given alignment. 
  127.  * The offset is the address of the start of the buffer, since it may
  128.  * not be aligned.  To align a pointer we add in the alignment minus one,
  129.  * then subtract the original alignment (low bits of the offset). 
  130.  * The address is then rounded to the alignment by anding with the inverse
  131.  * of the alignment minus one.  The original alignment is then added back in.
  132.  */
  133.  
  134. #define AlignPointer(align, offset, ptr) { \
  135.     (ptr) = (char *) (( \
  136.     (((int)(ptr)) + (align) - 1 - (((int) offset) & ((align)-1))) \
  137.     & ~((align)-1)) \
  138.     + (((int)offset) & ((align)-1))); \
  139. }
  140.  
  141. /*
  142.  * Return the maximum of two numbers.
  143.  */
  144. #define MAX(a,b) ((a) > (b)) ? (a) : (b)
  145.  
  146. /*
  147.  *----------------------------------------------------------------------
  148.  *
  149.  * Fmt_Convert --
  150.  *
  151.  *    Convert data from one format to another.
  152.  *    See the man page for more details.
  153.  *
  154.  * Results:
  155.  *    Data is read from the input buffer using the input format
  156.  *    and written to the output buffer using the output format.
  157.  *    *inSizePtr contains the actual number of input bytes used
  158.  *    and *outSizePtr contains the actual number of output bytes used.
  159.  *
  160.  *    Returns:
  161.  *    FMT_OK            -- conversion successful.
  162.  *    FMT_CONTENT_ERROR     -- error in content string
  163.  *    FMT_INPUT_TOO_SMALL    -- size of input buffer is smaller than that
  164.  *                   indicated by content string
  165.  *    FMT_OUTPUT_TOO_SMALL    -- output buffer is too small
  166.  *    FMT_ILLEGAL_FORMAT    -- one of the formats is bad
  167.  *
  168.  * Side effects:
  169.  *    None.
  170.  *
  171.  *----------------------------------------------------------------------
  172.  */
  173.  
  174. int
  175. Fmt_Convert(contents, inFormat, inSizePtr, inBuf, outFormat, outSizePtr, outBuf)
  176.     char        *contents;    /* String describing contents of 
  177.                      * buffers. */
  178.     Fmt_Format        inFormat;    /* Data format of input buffer */
  179.     int            *inSizePtr;    /* Ptr to size of input buffer */
  180.     char        *inBuf;        /* Input buffer */
  181.     Fmt_Format        outFormat;    /* Data format of output buffer */
  182.     int            *outSizePtr;    /* Ptr to size of output buffer */
  183.     char        *outBuf;    /* Output buffer */
  184. {
  185.  
  186.     State    state;
  187.     int        status;
  188.  
  189.     if ((inFormat & 0x1000) != 0) {
  190.     inFormat &= ~0x1000;
  191.     } else {
  192.     inFormat = compat[inFormat];
  193.     }
  194.     if ((outFormat & 0x1000) != 0) {
  195.     outFormat &= ~0x1000;
  196.     } else {
  197.     outFormat = compat[outFormat];
  198.     }
  199.  
  200.     if (inFormat < 1 || inFormat > formatCount) {
  201.     return FMT_ILLEGAL_FORMAT;
  202.     } 
  203.     if (outFormat < 1 || outFormat > formatCount) {
  204.     return FMT_ILLEGAL_FORMAT;
  205.     } 
  206.     state.contPtr = contents;
  207.     state.inEndPtr = inBuf + *inSizePtr;
  208.     state.inPtr = inBuf;
  209.     state.inStartPtr = inBuf;
  210.     state.outEndPtr = outBuf + *outSizePtr;
  211.     state.outPtr = outBuf;
  212.     state.outStartPtr = outBuf;
  213.     state.inInfoPtr = &(formatInfo[inFormat-1]);
  214.     state.outInfoPtr = &(formatInfo[outFormat-1]);
  215.  
  216.     status = ConvertSequence(TRUE, -1, '\0', &state);
  217.  
  218.     *inSizePtr = (int) (state.inPtr - inBuf);
  219.     *outSizePtr = (int) (state.outPtr - outBuf);
  220.  
  221.     return status;
  222. }
  223.  
  224. /*
  225.  *----------------------------------------------------------------------
  226.  *
  227.  * Fmt_Size --
  228.  *    Compute the size of the data after conversion.
  229.  *    See the man page for more details.
  230.  *
  231.  * Results:
  232.  *    Data is read from the input buffer using the input format
  233.  *    and written to the output buffer using the output format.
  234.  *    *inSizePtr contains the actual number of input bytes used.
  235.  *    *outSizePtr contains the size of the input data after conversion.
  236.  *
  237.  *    Returns:
  238.  *    FMT_OK            -- size calculation successful.
  239.  *    FMT_CONTENT_ERROR     -- error in content string
  240.  *    FMT_INPUT_TOO_SMALL    -- size of input buffer is smaller than that
  241.  *                   indicated by content string
  242.  *    FMT_ILLEGAL_FORMAT    -- one of the formats is bad
  243.  *
  244.  * Side effects:
  245.  *    None.
  246.  *
  247.  *----------------------------------------------------------------------
  248.  */
  249.  
  250. int
  251. Fmt_Size(contents, inFormat, inSizePtr, outFormat, outSizePtr)
  252.     char        *contents;    /* String describing contents of 
  253.                      * buffers. */
  254.     Fmt_Format        inFormat;    /* Data format of input buffer */
  255.     int            *inSizePtr;    /* Ptr to size of input buffer */
  256.     Fmt_Format        outFormat;    /* Data format of output buffer */
  257.     int            *outSizePtr;    /* Ptr to size of output buffer */
  258. {
  259.  
  260.     State    state;
  261.     int        status;
  262.  
  263.     if ((inFormat & 0x1000) != 0) {
  264.     inFormat &= ~0x1000;
  265.     } else {
  266.     inFormat = compat[inFormat];
  267.     }
  268.     if ((outFormat & 0x1000) != 0) {
  269.     outFormat &= ~0x1000;
  270.     } else {
  271.     outFormat = compat[outFormat];
  272.     }
  273.  
  274.     if (inFormat < 1 || inFormat > formatCount) {
  275.     return FMT_ILLEGAL_FORMAT;
  276.     } 
  277.     if (outFormat < 1 || outFormat > formatCount) {
  278.     return FMT_ILLEGAL_FORMAT;
  279.     } 
  280.     state.contPtr = contents;
  281.     state.inEndPtr = (char *) *inSizePtr;
  282.     state.inPtr = NULL;
  283.     state.outEndPtr = NULL;
  284.     state.outPtr = NULL;
  285.     state.inInfoPtr = &(formatInfo[inFormat-1]);
  286.     state.outInfoPtr = &(formatInfo[outFormat-1]);
  287.  
  288.     status = ConvertSequence(FALSE, -1, '\0', &state);
  289.  
  290.     *inSizePtr = (int) (state.inPtr);
  291.     *outSizePtr = (int) (state.outPtr);
  292.  
  293.     return status;
  294. }
  295.  
  296. /*
  297.  *----------------------------------------------------------------------
  298.  *
  299.  * ConvertSequence --
  300.  *
  301.  *    The conversion process is broken up in a hierarchical manner.
  302.  *    At the leaves are the conversions of bytes, halfwords, words and 
  303.  *    doublewords. Structures and unions are converted by converting
  304.  *    their components. These may be leaves, or they may be nested
  305.  *    structures and unions. Sequences are collections of conversions
  306.  *    at the same nesting level. The initial content string represents
  307.  *    a sequence of conversions, as do the fields of a structure.
  308.  *    The conversion of sequences requires no special alignment like
  309.  *    the other types of conversion.
  310.  *
  311.  *    The doCopy and unionIndex parameters can be used to control the
  312.  *    conversion. If doCopy is FALSE then the output buffer is not
  313.  *    modified. If unionIndex is >= 0, then only one element of the
  314.  *    sequence will be copied into the output buffer (if doCopy is TRUE).
  315.  *    If unionIndex < 0 then the sequence is not the components of a
  316.  *    union so they are all copied (if doCopy is TRUE).  If we are
  317.  *    processing a union the pointers to the input and output buffers
  318.  *    will be adjusted as if the largest element in the sequence had been
  319.  *    copied. For example, the union "(0bw)" should have the byte copied,
  320.  *    but the size of the union is 4 bytes. Keeping track of the largest
  321.  *    component allows the pointers to be advanced to the end of the
  322.  *    union.
  323.  *
  324.  * Results:
  325.  *    The state structure is modified to reflect the current state of
  326.  *    the conversion. Data may be copied from the input buffer to
  327.  *    the output buffer.
  328.  *
  329.  *    Returns:
  330.  *    FMT_OK            -- conversion successful.
  331.  *    FMT_CONTENT_ERROR     -- error in content string
  332.  *    FMT_INPUT_TOO_SMALL    -- size of input buffer is smaller than that
  333.  *                   indicated by content string
  334.  *    FMT_OUTPUT_TOO_SMALL    -- output buffer is too small
  335.  *
  336.  * Side effects:
  337.  *    None.
  338.  *
  339.  *----------------------------------------------------------------------
  340.  */
  341.  
  342. static int
  343. ConvertSequence(doCopy, unionIndex, openChar, statePtr)
  344.     Boolean        doCopy;        /* FALSE => don't modify the
  345.                      * output buffer. */
  346.     int            unionIndex;    /* If >= 0 then we are doing a union
  347.                      * so only copy this element and set
  348.                      * pointers to max of elements. */
  349.     char        openChar;    /* The character that started the 
  350.                      * sequence. */
  351.     register State    *statePtr;    /* Current state of conversion */
  352. {
  353.     register char     *contPtr;
  354.     int            status;
  355.     int            repCount;
  356.     char        *afterPtr;
  357.     int            curIndex;
  358.     char        *maxInPtr = (char *)NIL;
  359.     char        *maxOutPtr = (char *)NIL;
  360.     Boolean        doSubCopy;
  361.     char        *startInPtr = (char *)NIL;
  362.     char         *startOutPtr = (char *)NIL;
  363.  
  364.     status = FMT_OK;
  365.     curIndex = 0;
  366.     /*
  367.      * If we are doing a union keep track of where we started and the
  368.      * maximum  pointer values.
  369.      */
  370.     if (unionIndex >= 0) {
  371.     maxInPtr = statePtr->inPtr;
  372.     startInPtr = statePtr->inPtr;
  373.     maxOutPtr = statePtr->outPtr;
  374.     startOutPtr = statePtr->outPtr;
  375.     }
  376.     contPtr = statePtr->contPtr;
  377.     while (*contPtr != '\0') {
  378.     doSubCopy = doCopy && ((unionIndex < 0) || (unionIndex == curIndex));
  379.     switch (*contPtr) {
  380.         case '{' :
  381.         status = ConvertStruct(doSubCopy, unionIndex >= 0,  
  382.                 statePtr, &repCount);
  383.         break;
  384.         case '(' :
  385.         status = ConvertUnion(doSubCopy, unionIndex >= 0,  
  386.                 statePtr, &repCount);
  387.         break;
  388.         case '}' :
  389.         if (openChar != '{') {
  390.             return FMT_CONTENT_ERROR;
  391.         } else {
  392.             statePtr->contPtr = contPtr+1;
  393.             goto exit;
  394.         }
  395.         break;
  396.         case ')' :
  397.         if (openChar != '(') {
  398.             return FMT_CONTENT_ERROR;
  399.         } else {
  400.             statePtr->contPtr = contPtr+1;
  401.             goto exit;
  402.         }
  403.         break;
  404.         default : 
  405.         repCount = 1;
  406.         contPtr++;
  407.         /*
  408.          * Suck up strings of the same character. If we are doing
  409.          * a union we can't do this because they represent different
  410.          * components, not repeated data types within the same
  411.          * component. 
  412.          */
  413.         if (unionIndex < 0) {
  414.             while (*contPtr == *(contPtr-1)) {
  415.             contPtr++;
  416.             repCount++;
  417.             }
  418.         }
  419.         /*
  420.          * Get the repeat count if there is one.
  421.          */
  422.         if ((*contPtr >= '0') && (*contPtr <= '9')) {
  423.             repCount += strtoul(contPtr, &afterPtr, 10) - 1;
  424.             if (contPtr == afterPtr) {
  425.             return FMT_CONTENT_ERROR;
  426.             }
  427.         } else if (*contPtr == '*') {
  428.             repCount = -1;
  429.             afterPtr = contPtr + 1;
  430.         } else {
  431.             afterPtr = contPtr;
  432.         }
  433.         contPtr--;
  434.         if (repCount != 0) {
  435.             switch(*contPtr) {
  436.             case 'b' :
  437.                 status = ConvertByte(doSubCopy, 
  438.                         repCount, statePtr);
  439.                 break;
  440.             case 'h' :
  441.                 status = ConvertHalfWord(doSubCopy,  
  442.                         repCount, statePtr);
  443.                 break;
  444.             case 'w' :
  445.                 status = ConvertWord(doSubCopy, 
  446.                         repCount, statePtr);
  447.                 break;
  448.             case 'd' :
  449.                 status = ConvertDoubleWord(doSubCopy, 
  450.                         repCount, statePtr);
  451.                 break;
  452.             default :
  453.                 return FMT_CONTENT_ERROR;
  454.                 break;
  455.             }
  456.         }
  457.         contPtr = statePtr->contPtr = afterPtr;
  458.     }
  459.     if (status) {
  460.         return status;
  461.     }
  462.     curIndex += 1;
  463.     contPtr = statePtr->contPtr;
  464.     /*
  465.      * Save the max and reset the buffer pointers.
  466.      */
  467.     if (unionIndex >= 0) {
  468.         maxInPtr = MAX(maxInPtr, statePtr->inPtr);
  469.         maxOutPtr = MAX(maxOutPtr, statePtr->outPtr);
  470.         statePtr->inPtr = startInPtr;
  471.         statePtr->outPtr = startOutPtr;
  472.     }
  473.     }
  474. exit:
  475.     if (unionIndex >= 0) {
  476.     statePtr->inPtr = maxInPtr;
  477.     statePtr->outPtr = maxOutPtr;
  478.     }
  479.     return status;
  480. }
  481.  
  482.  
  483. /*
  484.  *----------------------------------------------------------------------
  485.  *
  486.  * ConvertStruct --
  487.  *
  488.  *    Process a structure conversion. Unlike simple data types, we don't
  489.  *    recognize strings of repeated structures. If the same structure is
  490.  *    repeated twice then we parse it twice. If a structure definition
  491.  *    is followed by a repeat count, then we parse the definition multiple
  492.  *    times also. It's too hard to do it differently. Also, since structure
  493.  *    definitions are variable length the repeat count is not passed in
  494.  *    by the calling procedure.  We pass it out instead.
  495.  *    
  496.  *    The doingUnion flag indicates that the structure is a member of a
  497.  *    union. If it is followed by a repeat count then only convert one
  498.  *    of them.
  499.  *
  500.  * Results:
  501.  *    Contents of the state record are modified to represent the
  502.  *    current state of the conversion. The content pointer is advanced
  503.  *    over the description of the structure and its rep count. 
  504.  *    inPtr and outPtr are advanced.
  505.  *    
  506.  *    Returns:
  507.  *    FMT_OK            -- conversion successful.
  508.  *    FMT_CONTENT_ERROR     -- error in content string
  509.  *    FMT_INPUT_TOO_SMALL    -- size of input buffer is smaller than that
  510.  *                   indicated by content string
  511.  *    FMT_OUTPUT_TOO_SMALL    -- output buffer is too small
  512.  *
  513.  * Side effects:
  514.  *    None.
  515.  *
  516.  *----------------------------------------------------------------------
  517.  */
  518.  
  519. static int
  520. ConvertStruct(doCopy, doingUnion, statePtr, repCountPtr)
  521.     Boolean        doCopy;     /* FALSE => don't modify output
  522.                      * buffer. */
  523.     Boolean        doingUnion;    /* TRUE => ignore rep count and only
  524.                      * convert one. */
  525.     register State    *statePtr;    /* Current state of conversion */
  526.     int            *repCountPtr;    /* Number of repetitions. */
  527. {
  528.  
  529.     char        *contPtr;
  530.     char        *afterPtr;
  531.     int            status;
  532.     int            repCount;
  533.     register int    count;
  534.     int            inAlign;
  535.     int            outAlign;
  536.  
  537.     afterPtr = statePtr->contPtr;
  538.     status = CalcComplexAlign(statePtr, &afterPtr, &repCount, &inAlign, 
  539.             &outAlign);
  540.     if (status) {
  541.     return status;
  542.     }
  543.     if (doingUnion) {
  544.     count = 1;
  545.     } else {
  546.     count = repCount;
  547.     }
  548.     contPtr = statePtr->contPtr + 1;
  549.     for (; count != 0; count--) {
  550.     AlignPointer(inAlign, statePtr->inStartPtr, statePtr->inPtr);
  551.     AlignPointer(outAlign, statePtr->outStartPtr, statePtr->outPtr);
  552.     /*
  553.      * If the structure is followed by a '*' and we are at the end of
  554.      * the input buffer then bail out.
  555.      */
  556.     if ((count < 0) && (statePtr->inPtr == statePtr->inEndPtr)) {
  557.         break;
  558.     }
  559.     statePtr->contPtr = contPtr;
  560.     status = ConvertSequence(doCopy, -1, '{', statePtr);
  561.     if (status) {
  562.         return status;
  563.     }
  564.     }
  565.     /*
  566.      * Structure size is always a multiple of the alignment.
  567.      */
  568.     AlignPointer(inAlign, statePtr->inStartPtr, statePtr->inPtr);
  569.     AlignPointer(outAlign, statePtr->outStartPtr, statePtr->outPtr);
  570.     statePtr->contPtr = afterPtr;
  571.     *repCountPtr = repCount;
  572.     return status;
  573.  
  574. }
  575.  
  576.  
  577. /*
  578.  *----------------------------------------------------------------------
  579.  *
  580.  * ConvertUnion --
  581.  *
  582.  *    Process a union conversion. The comments for ConvertStruct apply.
  583.  *    The opening parenthesis of a union definition is followed by the
  584.  *    discriminator (index of the element to be copied). This discriminator
  585.  *    is passed to ConvertSequence so only that element is copied.
  586.  *
  587.  * Results:
  588.  *    Contents of the state record are modified to represent the
  589.  *    current state of the conversion. The content pointer is advanced
  590.  *    over the description of the union and its rep count. 
  591.  *    inPtr and outPtr are advanced.
  592.  *
  593.  *    Returns:
  594.  *    FMT_OK            -- conversion successful.
  595.  *    FMT_CONTENT_ERROR     -- error in content string
  596.  *    FMT_INPUT_TOO_SMALL    -- size of input buffer is smaller than that
  597.  *                   indicated by content string
  598.  *    FMT_OUTPUT_TOO_SMALL    -- output buffer is too small
  599.  *
  600.  * Side effects:
  601.  *    None.
  602.  *
  603.  *----------------------------------------------------------------------
  604.  */
  605.  
  606. static int
  607. ConvertUnion(doCopy, doingUnion, statePtr, repCountPtr)
  608.     Boolean        doCopy;     /* FALSE => don't modify output
  609.                      * buffer. */
  610.     Boolean        doingUnion;    /* TRUE => ignore rep count and only
  611.                      * convert one. */
  612.     register State    *statePtr;    /* Current state of conversion */
  613.     int            *repCountPtr;    /* Number of repetitions. */
  614. {
  615.  
  616.     char        *contPtr;
  617.     char        *afterPtr;
  618.     int            status;
  619.     int            repCount;
  620.     register int    count;
  621.     char        *tempPtr;
  622.     int            index;
  623.     int            inAlign;
  624.     int            outAlign;
  625.  
  626.     afterPtr = statePtr->contPtr;
  627.     status = CalcComplexAlign(statePtr, &afterPtr, &repCount, &inAlign, 
  628.             &outAlign);
  629.     if (status) {
  630.     return status;
  631.     }
  632.     if (doingUnion) {
  633.     count = 1;
  634.     } else {
  635.     count = repCount;
  636.     }
  637.     contPtr = statePtr->contPtr + 1;
  638.     /*
  639.      * Get the discriminator.
  640.      */
  641.     if ((*contPtr >= '0') && (*contPtr <= '9')) {
  642.     index = strtoul(contPtr, &tempPtr, 10);
  643.     if (contPtr == tempPtr) {
  644.         return FMT_CONTENT_ERROR;
  645.     }
  646.     } else {
  647.     return FMT_CONTENT_ERROR;
  648.     }
  649.     contPtr = tempPtr;
  650.     for (; count != 0; count--) {
  651.     AlignPointer(inAlign, statePtr->inStartPtr, statePtr->inPtr);
  652.     AlignPointer(outAlign, statePtr->outStartPtr, statePtr->outPtr);
  653.     /*
  654.      * If the union is followed by a '*' and we are at the end of
  655.      * the input buffer then bail out.
  656.      */
  657.     if ((count < 0) && (statePtr->inPtr == statePtr->inEndPtr)) {
  658.         break;
  659.     }
  660.     statePtr->contPtr = contPtr;
  661.     status = ConvertSequence(doCopy, index, '(', statePtr);
  662.     if (status) {
  663.         return status;
  664.     }
  665.     }
  666.     AlignPointer(inAlign, statePtr->inStartPtr, statePtr->inPtr);
  667.     AlignPointer(outAlign, statePtr->outStartPtr, statePtr->outPtr);
  668.     statePtr->contPtr = afterPtr;
  669.     *repCountPtr = repCount;
  670.     return status;
  671. }
  672.  
  673.  
  674. /*
  675.  *----------------------------------------------------------------------
  676.  *
  677.  * ConvertByte --
  678.  *
  679.  *    If doCopy is TRUE, then copy bytes from the input buffer to the
  680.  *    output buffer. Otherwise just advance the buffer pointers.
  681.  *    If either buffer is too small then return an error. An exception
  682.  *     is made if the pointer to the end of the output buffer is NULL.
  683.  *    This indicates that there isn't an output buffer.
  684.  *
  685.  * Results:
  686.  *    The contents of the state structure are modified to reflect the
  687.  *    current state of the conversion. The input and output pointers
  688.  *    are aligned and advanced repCount bytes.
  689.  *
  690.  *    Returns:
  691.  *    FMT_OK            -- conversion successful.
  692.  *    FMT_INPUT_TOO_SMALL    -- input buffer is too small
  693.  *    FMT_OUTPUT_TOO_SMALL    -- output buffer is too small
  694.  *
  695.  * Side effects:
  696.  *    None.
  697.  *
  698.  *----------------------------------------------------------------------
  699.  */
  700.  
  701. static int
  702. ConvertByte(doCopy, repCount, statePtr)
  703.     Boolean        doCopy;        /* TRUE => modify output buffer. */
  704.     int            repCount;    /* Number of bytes to copy. */
  705.     State        *statePtr;    /* Current state of conversion. */
  706. {
  707.     register int    i;
  708.     register char    *inPtr;
  709.     register char    *outPtr;
  710.     int            status;
  711.  
  712.     inPtr = statePtr->inPtr;
  713.     outPtr = statePtr->outPtr;
  714.     status = FMT_OK;
  715.  
  716.     AlignPointer(statePtr->inInfoPtr->bAlign, statePtr->inStartPtr, inPtr);
  717.     AlignPointer(statePtr->outInfoPtr->bAlign, statePtr->outStartPtr, outPtr);
  718.  
  719.     if (repCount > 0) {
  720.     if (inPtr + repCount  > statePtr->inEndPtr) {
  721.         status = FMT_INPUT_TOO_SMALL;
  722.         repCount = statePtr->inEndPtr - inPtr;
  723.     }
  724.     } else {
  725.     repCount = statePtr->inEndPtr - inPtr;
  726.     }
  727.     if (statePtr->outEndPtr != NULL && 
  728.     outPtr + repCount > statePtr->outEndPtr) {
  729.     status = FMT_OUTPUT_TOO_SMALL;
  730.     repCount = statePtr->outEndPtr - outPtr;
  731.     }
  732.     if (doCopy) {
  733.     for (i = 0; i < repCount; i++) {
  734.         *outPtr = *inPtr;
  735.         outPtr++;
  736.         inPtr++;
  737.     }
  738.     } else {
  739.     inPtr += repCount;
  740.     outPtr += repCount;
  741.     }
  742.  
  743.     statePtr->inPtr = inPtr;
  744.     statePtr->outPtr = outPtr;
  745.     return status;
  746. }
  747.  
  748.  
  749. /*
  750.  *----------------------------------------------------------------------
  751.  *
  752.  * ConvertHalfWord --
  753.  *
  754.  *    If doCopy is TRUE, then copy halfwords from the input buffer to the
  755.  *    output buffer. Otherwise just advance the buffer pointers.
  756.  *    If either buffer is too small then return an error. An exception
  757.  *     is made if the pointer to the end of the output buffer is NULL.
  758.  *    This indicates that there isn't an output buffer.
  759.  *
  760.  * Results:
  761.  *    The contents of the state structure are modified to reflect the
  762.  *    current state of the conversion. The input and output pointers
  763.  *    are aligned and advanced repCount halfwords.
  764.  *
  765.  *    Returns:
  766.  *    FMT_OK            -- conversion successful.
  767.  *    FMT_INPUT_TOO_SMALL    -- input buffer is too small
  768.  *    FMT_OUTPUT_TOO_SMALL    -- output buffer is too small
  769.  *
  770.  * Side effects:
  771.  *    None.
  772.  *
  773.  *----------------------------------------------------------------------
  774.  */
  775.  
  776. static int
  777. ConvertHalfWord(doCopy, repCount, statePtr)
  778.     Boolean        doCopy;        /* TRUE => modify output buffer. */
  779.     int            repCount;    /* Number of halfwords to copy. */
  780.     State        *statePtr;    /* Current state of conversion. */
  781. {
  782.     register int    i;
  783.     register char    *inPtr;
  784.     register char    *outPtr;
  785.     int            status;
  786.  
  787.     inPtr = statePtr->inPtr;
  788.     outPtr = statePtr->outPtr;
  789.     status = FMT_OK;
  790.  
  791.  
  792.     AlignPointer(statePtr->inInfoPtr->hAlign, statePtr->inStartPtr, inPtr);
  793.     AlignPointer(statePtr->outInfoPtr->hAlign, statePtr->outStartPtr, outPtr);
  794.  
  795.     if (repCount > 0) {
  796.     if (inPtr + repCount * 2  > statePtr->inEndPtr) {
  797.         status = FMT_INPUT_TOO_SMALL;
  798.         repCount = (((int) statePtr->inEndPtr) - ((int) inPtr)) / 2;
  799.     }
  800.     } else if (repCount < 0) {
  801.     repCount = (((int) statePtr->inEndPtr) - ((int) inPtr)) / 2;
  802.     } else {
  803.     return status;
  804.     }
  805.     if (statePtr->outEndPtr != NULL && 
  806.         outPtr + repCount * 2 > statePtr->outEndPtr) {
  807.     status = FMT_OUTPUT_TOO_SMALL;
  808.     repCount = (((int) statePtr->outEndPtr) - ((int) repCount)) / 2;
  809.     }
  810.     if (doCopy) {
  811.     if (statePtr->inInfoPtr->byteOrder == 
  812.         statePtr->outInfoPtr->byteOrder) { 
  813.  
  814.         for (i = 0; i < repCount; i++) {
  815.         outPtr[0] = inPtr[0];
  816.         outPtr[1] = inPtr[1];
  817.         inPtr += 2;
  818.         outPtr += 2;
  819.         }
  820.     } else {
  821.         for (i = 0; i < repCount; i++) {
  822.         outPtr[0] = inPtr[1];
  823.         outPtr[1] = inPtr[0];
  824.         inPtr += 2;
  825.         outPtr += 2;
  826.         }
  827.     }
  828.     } else {
  829.     inPtr += repCount * 2;
  830.     outPtr += repCount * 2;
  831.     }
  832.     statePtr->inPtr = inPtr;
  833.     statePtr->outPtr = outPtr;
  834.     return status;
  835. }
  836.  
  837. /*
  838.  *----------------------------------------------------------------------
  839.  *
  840.  * ConvertWord --
  841.  *
  842.  *    If doCopy is TRUE, then copy words from the input buffer to the
  843.  *    output buffer. Otherwise just advance the buffer pointers.
  844.  *    If either buffer is too small then return an error. An exception
  845.  *     is made if the pointer to the end of the output buffer is NULL.
  846.  *    This indicates that there isn't an output buffer.
  847.  *
  848.  * Results:
  849.  *    The contents of the state structure are modified to reflect the
  850.  *    current state of the conversion. The input and output pointers
  851.  *    are aligned and advanced repCount words.
  852.  *
  853.  *    Returns:
  854.  *    FMT_OK            -- conversion successful.
  855.  *    FMT_INPUT_TOO_SMALL    -- input buffer is too small
  856.  *    FMT_OUTPUT_TOO_SMALL    -- output buffer is too small
  857.  *
  858.  * Side effects:
  859.  *    None.
  860.  *
  861.  *----------------------------------------------------------------------
  862.  */
  863.  
  864. static int
  865. ConvertWord(doCopy, repCount, statePtr)
  866.     Boolean        doCopy;        /* TRUE => modify output buffer. */
  867.     int            repCount;    /* Number of words to copy. */
  868.     State        *statePtr;    /* Current state of conversion. */
  869. {
  870.     register int    i;
  871.     register char    *inPtr;
  872.     register char    *outPtr;
  873.     int            status;
  874.  
  875.     inPtr = statePtr->inPtr;
  876.     outPtr = statePtr->outPtr;
  877.     status = FMT_OK;
  878.  
  879.     AlignPointer(statePtr->inInfoPtr->wAlign, statePtr->inStartPtr, inPtr);
  880.     AlignPointer(statePtr->outInfoPtr->wAlign, statePtr->outStartPtr, outPtr);
  881.  
  882.     if (repCount > 0) {
  883.     if (inPtr + repCount * 4 > statePtr->inEndPtr) {
  884.         status = FMT_INPUT_TOO_SMALL;
  885.         repCount = (((int) statePtr->inEndPtr) - ((int) inPtr)) / 4;
  886.     }
  887.     } else if (repCount < 0) {
  888.     repCount = (((int) statePtr->inEndPtr) - ((int) inPtr)) / 4;
  889.     } else {
  890.     return status;
  891.     }
  892.     if (statePtr->outEndPtr != NULL && 
  893.         outPtr + repCount * 4 > statePtr->outEndPtr) {
  894.     status = FMT_OUTPUT_TOO_SMALL;
  895.     repCount = ((int) statePtr->outEndPtr - ((int) outPtr)) / 4;
  896.     }
  897.     if (doCopy) {
  898.     if (statePtr->inInfoPtr->byteOrder == 
  899.         statePtr->outInfoPtr->byteOrder) { 
  900.         for (i = 0; i < repCount; i++) {
  901.         outPtr[0] = inPtr[0];
  902.         outPtr[1] = inPtr[1];
  903.         outPtr[2] = inPtr[2];
  904.         outPtr[3] = inPtr[3];
  905.         inPtr += 4;
  906.         outPtr += 4;
  907.         }
  908.     } else {
  909.         for (i = 0; i < repCount; i++) {
  910.         outPtr[0] = inPtr[3];
  911.         outPtr[1] = inPtr[2];
  912.         outPtr[2] = inPtr[1];
  913.         outPtr[3] = inPtr[0];
  914.         inPtr += 4;
  915.         outPtr += 4;
  916.         }
  917.     }
  918.     } else {
  919.     inPtr += repCount * 4;
  920.     outPtr += repCount * 4;
  921.     }
  922.     statePtr->inPtr = inPtr;
  923.     statePtr->outPtr = outPtr;
  924.     return status;
  925. }
  926.  
  927. /*
  928.  *----------------------------------------------------------------------
  929.  *
  930.  * ConvertDoubleWord --
  931.  *
  932.  *    If doCopy is TRUE, then copy doublewords from the input buffer to
  933.  *    the output buffer. Otherwise just advance the buffer pointers.  If
  934.  *    either buffer is too small then return an error. An exception is
  935.  *    made if the pointer to the end of the output buffer is NULL.  This
  936.  *    indicates that there isn't an output buffer.
  937.  *
  938.  * Results:
  939.  *    The contents of the state structure are modified to reflect the
  940.  *    current state of the conversion. The input and output pointers
  941.  *    are aligned and advanced repCount doublewords.
  942.  *    
  943.  *    Returns:
  944.  *    FMT_OK            -- conversion successful.
  945.  *    FMT_INPUT_TOO_SMALL    -- input buffer is too small
  946.  *    FMT_OUTPUT_TOO_SMALL    -- output buffer is too small
  947.  *
  948.  * Side effects:
  949.  *    None.
  950.  *
  951.  *----------------------------------------------------------------------
  952.  */
  953.  
  954. static int
  955. ConvertDoubleWord(doCopy, repCount, statePtr)
  956.     Boolean        doCopy;        /* TRUE => modify output buffer. */
  957.     int            repCount;    /* Number of doublewords to copy. */
  958.     State        *statePtr;    /* Current state of conversion. */
  959. {
  960.     register int    i;
  961.     register char    *inPtr;
  962.     register char    *outPtr;
  963.     int            status;
  964.  
  965.     inPtr = statePtr->inPtr;
  966.     outPtr = statePtr->outPtr;
  967.     status = FMT_OK;
  968.  
  969.     AlignPointer(statePtr->inInfoPtr->dAlign, statePtr->inStartPtr, inPtr);
  970.     AlignPointer(statePtr->outInfoPtr->dAlign, statePtr->outStartPtr, outPtr);
  971.  
  972.     if (repCount > 0) {
  973.     if (inPtr + repCount * 8 > statePtr->inEndPtr) {
  974.         status = FMT_INPUT_TOO_SMALL;
  975.         repCount = (((int) statePtr->inEndPtr) - ((int) inPtr)) / 8;
  976.     }
  977.     } else if (repCount < 0) {
  978.     repCount = (((int) statePtr->inEndPtr) - ((int) inPtr)) / 8;
  979.     } else {
  980.     return status;
  981.     }
  982.     if (statePtr->outEndPtr != NULL && 
  983.         outPtr + repCount * 8 > statePtr->outEndPtr) {
  984.     status = FMT_OUTPUT_TOO_SMALL;
  985.     repCount = (((int) statePtr->outEndPtr) - ((int) outPtr)) / 8;
  986.     }
  987.     if (doCopy) {
  988.     if (statePtr->inInfoPtr->byteOrder == 
  989.         statePtr->outInfoPtr->byteOrder) { 
  990.  
  991.         for (i = 0; i < repCount; i++) {
  992.         outPtr[0] = inPtr[0];
  993.         outPtr[1] = inPtr[1];
  994.         outPtr[2] = inPtr[2];
  995.         outPtr[3] = inPtr[3];
  996.         outPtr[4] = inPtr[4];
  997.         outPtr[5] = inPtr[5];
  998.         outPtr[6] = inPtr[6];
  999.         outPtr[7] = inPtr[7];
  1000.         inPtr += 8;
  1001.         outPtr += 8;
  1002.         }
  1003.     } else {
  1004.         for (i = 0; i < repCount; i++) {
  1005.         outPtr[0] = inPtr[7];
  1006.         outPtr[1] = inPtr[6];
  1007.         outPtr[2] = inPtr[5];
  1008.         outPtr[3] = inPtr[4];
  1009.         outPtr[4] = inPtr[3];
  1010.         outPtr[5] = inPtr[2];
  1011.         outPtr[6] = inPtr[1];
  1012.         outPtr[7] = inPtr[0];
  1013.         inPtr += 8;
  1014.         outPtr += 8;
  1015.         }
  1016.     }
  1017.     } else {
  1018.     inPtr += repCount * 8;
  1019.     outPtr += repCount * 8;
  1020.     }
  1021.     statePtr->inPtr = inPtr;
  1022.     statePtr->outPtr = outPtr;
  1023.     return status;
  1024. }
  1025.  
  1026. /*
  1027.  *----------------------------------------------------------------------
  1028.  *
  1029.  * CalcComplexAlign --
  1030.  *
  1031.  *    Calculate the alignment of a structure or a union. The alignment
  1032.  *    is the maximum of the alignment specified by the format and the
  1033.  *    alignments of the fields. The repeat count is read and returned
  1034.  *    in *repCountPtr. If the data type is followed by '*' then -1 is
  1035.  *    returned as the repeat count.
  1036.  *
  1037.  * Results:
  1038.  *    *contPtrPtr points to the first character after the data type
  1039.  *    definition and repeat count. *inAlignPtr contains the alignment
  1040.  *    for the in format, and *outAlignPtr contains the alignment for the
  1041.  *    out format. *repCountPtr contains the repeat count.
  1042.  *
  1043.  *    Returns:
  1044.  *    FMT_OK            -- conversion successful.
  1045.  *    FMT_CONTENT_ERROR     -- error in content string
  1046.  *
  1047.  * Side effects:
  1048.  *    None.
  1049.  *
  1050.  *----------------------------------------------------------------------
  1051.  */
  1052.  
  1053. static int
  1054. CalcComplexAlign(statePtr, contPtrPtr, repCountPtr, inAlignPtr, outAlignPtr)
  1055.     State         *statePtr;    /* Current state of conversion. */
  1056.     char        **contPtrPtr;    /* Ptr to ptr to content string */
  1057.     int            *repCountPtr;    /* Ptr to repeat count. */
  1058.     int            *inAlignPtr;    /* Ptr to in alignment. */
  1059.     int            *outAlignPtr;    /* Ptr to out alignment. */
  1060. {
  1061.     int                inAlign = 0; /* dummy initial value */
  1062.     int                outAlign = 0; /* dummy initial value */
  1063.     register char        *contPtr;
  1064.     Boolean            doingUnion = FALSE; /* dummy initial value */
  1065.     char            lastChar;
  1066.     int                status;
  1067.     int                repCount;
  1068.     char            *tempPtr;
  1069.     register FormatInfo        *inInfoPtr;
  1070.     register FormatInfo        *outInfoPtr;
  1071.  
  1072.     status = FMT_OK;
  1073.     contPtr = *contPtrPtr;
  1074.     inInfoPtr = statePtr->inInfoPtr;
  1075.     outInfoPtr = statePtr->outInfoPtr;
  1076.     switch (*contPtr) {
  1077.     case '{' :
  1078.         inAlign = inInfoPtr->structMinAlign;
  1079.         outAlign = outInfoPtr->structMinAlign;
  1080.         doingUnion = FALSE;
  1081.         break;
  1082.     case '(' :
  1083.         inAlign = inInfoPtr->unionMinAlign;
  1084.         outAlign = outInfoPtr->unionMinAlign;
  1085.         doingUnion = TRUE;
  1086.         break;
  1087.     default :
  1088.         panic("Fmt: Internal error: CalcComplexAlign called improperly.\n");
  1089.     }
  1090.     contPtr++;
  1091.     lastChar = '\0';
  1092.     while (*contPtr != '\0') {
  1093.     if (*contPtr == lastChar) {
  1094.         contPtr++;
  1095.         continue;
  1096.     }
  1097.     lastChar = *contPtr;
  1098.     if ((*contPtr >= '0') && (*contPtr <= '9')) {
  1099.         contPtr++;
  1100.         continue;
  1101.     }
  1102.     switch (*contPtr) {
  1103.         case 'b':
  1104.         inAlign = MAX(inAlign, inInfoPtr->bAlign);
  1105.         outAlign = MAX(outAlign, outInfoPtr->bAlign);
  1106.         contPtr++;
  1107.         break;
  1108.         case 'h':
  1109.         inAlign = MAX(inAlign, inInfoPtr->hAlign);
  1110.         outAlign = MAX(outAlign, outInfoPtr->hAlign);
  1111.         contPtr++;
  1112.         break;
  1113.         case 'w':
  1114.         inAlign = MAX(inAlign, inInfoPtr->wAlign);
  1115.         outAlign = MAX(outAlign, outInfoPtr->wAlign);
  1116.         contPtr++;
  1117.         break;
  1118.         case 'd':
  1119.         inAlign = MAX(inAlign, inInfoPtr->dAlign);
  1120.         outAlign = MAX(outAlign, outInfoPtr->dAlign);
  1121.         contPtr++;
  1122.         break;
  1123.         case '(':
  1124.         case '{': {
  1125.         int dummy;
  1126.         int tempInAlign;
  1127.         int tempOutAlign;
  1128.         char *tempContPtr;
  1129.         tempContPtr = contPtr;
  1130.         status = CalcComplexAlign(statePtr, &tempContPtr, &dummy, 
  1131.                 &tempInAlign, &tempOutAlign);
  1132.         if (status) {
  1133.             return status;
  1134.         }
  1135.         inAlign = MAX(inAlign, tempInAlign);
  1136.         outAlign = MAX(outAlign, tempOutAlign);
  1137.         contPtr = tempContPtr;
  1138.         lastChar = '\0';
  1139.         break;
  1140.         }
  1141.         case ')':
  1142.         if (!doingUnion) {
  1143.             return FMT_CONTENT_ERROR;
  1144.         }
  1145.         contPtr++;
  1146.         goto exit;
  1147.         break;
  1148.         case '}':
  1149.         if (doingUnion) {
  1150.             return FMT_CONTENT_ERROR;
  1151.         }
  1152.         contPtr++;
  1153.         goto exit;
  1154.         break;
  1155.         case '*' :
  1156.         contPtr++;
  1157.         break;
  1158.         default :
  1159.         return FMT_CONTENT_ERROR;
  1160.         break;
  1161.     }
  1162.     }
  1163.     return FMT_CONTENT_ERROR;
  1164. exit :
  1165.     /*
  1166.      * Parse the repeat count.
  1167.      */
  1168.     if ((*contPtr >= '0') && (*contPtr <= '9')) {
  1169.     repCount = strtoul(contPtr, &tempPtr, 10);
  1170.     if (contPtr == tempPtr) {
  1171.         return FMT_CONTENT_ERROR;
  1172.     }
  1173.     contPtr = tempPtr;
  1174.     } else if (*contPtr == '*') {
  1175.     repCount = -1;
  1176.     contPtr++;
  1177.     } else {
  1178.     repCount = 1;
  1179.     }
  1180.     *repCountPtr = repCount;
  1181.     *contPtrPtr = contPtr;
  1182.     *inAlignPtr = inAlign;
  1183.     *outAlignPtr = outAlign;
  1184.     return status;
  1185. }
  1186.  
  1187.